/*
Copyright (C) Ariff Ehsan, Abdul Hadi Fikri

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

/*  Author : Ariff Ehsan
 *           Abdul Hadi Fikri
 *  Date   : June 18, 2009
 */


#include <system.h>

/**
*Interface task{
*	provide{
*		command TASK_init();
*		command TASK_reg(task_t*t,void(*run)());
*		command TASK_post(task_t*t);
*		command TASK_run();
*	}
*	uses{
*		signal (*run)();
*	}
*}
*
*Private:
*	Data Field
*/		struct {
			task_t *p_start;
			task_t *p_last;
		}task_prop;
/**
 *  Function member:
 */		void TASK_insert(task_t *t);

/********************************************************************************************/
/*                              Clients Function Call                                       */
/********************************************************************************************/
/** 
 *  Register a task. Task MUST be registered
 *  *t		- pointer to a task to be registered
 *  *run	- pointer to task executing function
 */
void TASK_reg(task_t *t, void (*run)(void)) {
  
  ENTER_CRITICAL();

  t->scheduled = FALSE;
  t->run = run;

  EXIT_CRITICAL();

}
/**
 *  To post a task. A request to post a posted task will be ignored
 *  *t		- pointer to a task to be posted
 */
void TASK_post(task_t *t) {
  
	ENTER_CRITICAL();
	
	if (t->scheduled) {
		EXIT_CRITICAL();
		return;
	}

	t->scheduled = TRUE;
	TASK_insert(t);
	
	EXIT_CRITICAL();
}
/********************************************************************************************/
/*                                 Internal Function Call                                   */
/********************************************************************************************/
/**
*Used to insert task into scheduler
*/
void TASK_insert(task_t *t) {

  //ENTER_CRITICAL();

  if (task_prop.p_start == NULL) {
    task_prop.p_start = t;
	task_prop.p_last = t;

    //EXIT_CRITICAL();

	return;
  }

  t->next = NULL;

  (task_prop.p_last)->next = t;
  task_prop.p_last = t;

  //EXIT_CRITICAL();

}

/********************************************************************************************/
/*                              HW/SW Interrupt Function Call                               */
/********************************************************************************************/
/**
*Initialized by the system
*/
void TASK_init() {
  task_prop.p_start = NULL;
}
/**
*Polling the scheduler for tasks by the system
*/
void TASK_run() {

  ENTER_CRITICAL();

  if (task_prop.p_start == NULL) {
    // no task to run
	EXIT_CRITICAL();
	return;
  }

  task_t *t = task_prop.p_start;

  if (task_prop.p_start == task_prop.p_last) {
    task_prop.p_last = NULL;
  }

  task_prop.p_start = t->next;
  
  t->next = NULL;
  t->scheduled = FALSE;

  EXIT_CRITICAL();

  void (*run)(void) = t->run;
  (*run)();

}
/********************************************************************************************/

